using System;
using System.Collections.Generic;
using System.Text;

namespace OracleInternal.SqlAndPlsqlParser
{
	internal class ParseNode : IComparable
	{
		protected const int c_vMaxNodesToPrint = 1000;

		public List<int> m_vRulesUsed;

		protected int m_vFrom;

		protected int m_vTo;

		protected int m_vPayloadIn;

		protected ParseNode m_vParentNode;

		protected ParseNode m_vNextNode;

		protected ParseNode m_vFirstChildNode;

		protected List<ParseNode> m_vChildren;

		public int From
		{
			get
			{
				return m_vFrom;
			}
			set
			{
				m_vFrom = value;
			}
		}

		public int To => m_vTo;

		public int PayloadIn
		{
			get
			{
				return m_vPayloadIn;
			}
			set
			{
				m_vPayloadIn = value;
			}
		}

		public ParseNode ParentNode => m_vParentNode;

		public ParseNode NextNode => m_vNextNode;

		public ParseNode FirstChildNode => m_vFirstChildNode;

		public ParseNode(int begin, int end, int sIn, int sOut)
		{
			m_vFrom = begin;
			m_vTo = end;
			m_vPayloadIn = sIn;
		}

		public void AddChild(ParseNode pn)
		{
			pn.m_vNextNode = m_vFirstChildNode;
			m_vFirstChildNode = pn;
			pn.m_vParentNode = this;
		}

		public void AddUsedRule(int ruleIdx)
		{
			if (m_vRulesUsed == null)
			{
				m_vRulesUsed = new List<int>(1);
				m_vRulesUsed.Add(ruleIdx);
			}
			else
			{
				m_vRulesUsed.Insert(0, ruleIdx);
			}
		}

		public void AppendUsedRule(int ruleIdx)
		{
			if (m_vRulesUsed == null)
			{
				m_vRulesUsed = new List<int>(1);
			}
			m_vRulesUsed.Add(ruleIdx);
		}

		public int CompareTo(object obj)
		{
			ParseNode parseNode = (ParseNode)obj;
			if (parseNode == null)
			{
				return 1;
			}
			if (m_vFrom != parseNode.m_vFrom)
			{
				return m_vFrom - parseNode.m_vFrom;
			}
			return m_vTo - parseNode.m_vFrom;
		}

		public List<ParseNode> Children()
		{
			if (m_vChildren == null)
			{
				m_vChildren = new List<ParseNode>();
				for (ParseNode parseNode = m_vFirstChildNode; parseNode != null; parseNode = parseNode.m_vNextNode)
				{
					m_vChildren.Add(parseNode);
				}
			}
			return m_vChildren;
		}

		public virtual string ToString(ParserGrammarDefinition gd)
		{
			return ToString(0, gd);
		}

		public virtual string ToString(int depth, ParserGrammarDefinition gd)
		{
			int nodeCount = 0;
			StringBuilder sb = new StringBuilder(4098);
			Append(0, gd, ref sb, ref nodeCount);
			return sb.ToString();
		}

		protected bool Append(int depth, ParserGrammarDefinition gd, ref StringBuilder sb, ref int nodeCount)
		{
			Append(depth, gd, ref sb);
			if (++nodeCount == 1000)
			{
				sb.Append($"...\nThe limit of {1000} nodes to be displayed has been reached!");
				return false;
			}
			depth++;
			foreach (ParseNode item in Children())
			{
				if (!item.Append(depth, gd, ref sb, ref nodeCount))
				{
					return false;
				}
			}
			return true;
		}

		protected void Append(int depth, ParserGrammarDefinition gd, ref StringBuilder sb)
		{
			sb.Append(' ', 2 * depth);
			sb.Append('[');
			sb.Append(m_vFrom);
			sb.Append(',');
			sb.Append(m_vTo);
			sb.Append(") ");
			sb.Append(" | ");
			sb.Append(gd.m_vAllSymbols[m_vPayloadIn]);
			if (gd != null && m_vRulesUsed != null)
			{
				foreach (int item in m_vRulesUsed)
				{
					sb.Append(" | ");
					sb.Append(gd.m_vRules[item].ToString());
				}
			}
			sb.Append("\n");
		}

		public void PrintTree(ParserGrammarDefinition gd)
		{
			PrintTree(0, gd);
		}

		public void PrintTree(int depth, ParserGrammarDefinition gd)
		{
			Console.Write(ToString(depth, gd));
		}

		public string Content(List<LexerToken> src)
		{
			StringBuilder stringBuilder = new StringBuilder();
			for (int i = m_vFrom; i < m_vTo; i++)
			{
				stringBuilder.Append(src[i].m_vContent);
			}
			return stringBuilder.ToString();
		}
	}
}
